package com.ys.erp.framework.handler.login;

import com.alibaba.fastjson2.JSONObject;
import com.ys.erp.common.enums.RedisKey;
import com.ys.erp.common.util.YsThread;
import com.ys.erp.framework.annotation.AppletLoginEmp;
import com.ys.erp.framework.annotation.CheckEmpLogin;
import com.ys.erp.framework.annotation.StageLoginEmp;
import com.ys.erp.framework.bean.dto.AppletEmpDTO;
import com.ys.erp.framework.bean.dto.EmpDTO;
import com.ys.erp.framework.bean.dto.StageEmpDTO;
import com.ys.erp.framework.exception.YsException;
import com.ys.erp.framework.response.AbstractResponseCode;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Parameter;
import java.util.concurrent.TimeUnit;

/**
 * @author lwj
 * @date 2021/5/10
 */
@Component
@Aspect
@Slf4j
@RequiredArgsConstructor
public class EmpLoginHandler extends CheckEmpLoginHandler {

    private final RedisTemplate<String, String> redisTemplate;

    @Override
    public Object checkUserLogin(ProceedingJoinPoint pj, HttpServletRequest request, CheckEmpLogin checkUserLogin) throws Throwable {
        String tokenFlag = "token";
        log.info(request.getRequestURI());
        EmpDTO empDTO = null;
        String token = request.getHeader(tokenFlag);
        //获取校验注解
        Object[] args = pj.getArgs();
        MethodSignature signature = (MethodSignature) pj.getSignature();
        Parameter[] parameters = signature.getMethod().getParameters();
        Integer argFlag = null;
        String loginKey = null;
        for (int i = 0; i < parameters.length; i ++) {
            //清除前端传来的数据，保障安全
            if (args[i] instanceof EmpDTO) {
                args[i] = null;
            }
            StageLoginEmp stageAnnotation = parameters[i].getAnnotation(StageLoginEmp.class);
            if (stageAnnotation != null) {
                loginKey = RedisKey.Enums.EMP_LOGIN_FLAG.getKey() + token;
                argFlag = i;
                empDTO = new StageEmpDTO();
                break;
            }
            AppletLoginEmp appletAnnotation = parameters[i].getAnnotation(AppletLoginEmp.class);
            if (appletAnnotation != null) {
                loginKey = RedisKey.Enums.EMP_APPLET_LOGIN_FLAG.getKey() + token;
                //续期
                YsThread.execute(() -> {
                    redisTemplate.expire(RedisKey.Enums.EMP_APPLET_LOGIN_FLAG.getKey() + token, 7, TimeUnit.DAYS);
                });
                argFlag = i;
                empDTO = new AppletEmpDTO();
                break;
            }
        }
        // 获取注解配置，进行校验
        boolean required = checkUserLogin.mustLogin();
        if (required) {
            if (StringUtils.isBlank(token)) {
                //报错
                throw new YsException(AbstractResponseCode.AGAIN_LOGIN);
            }
            if (StringUtils.isBlank(loginKey)) {
                //报错
                throw new YsException(AbstractResponseCode.AGAIN_LOGIN);
            }
            String userDtoStr = redisTemplate.opsForValue().get(loginKey);
            if (ObjectUtils.isEmpty(userDtoStr)) {
                //token过期
                throw new YsException(AbstractResponseCode.AGAIN_LOGIN);
            }
            setUserArg(args, argFlag, empDTO, userDtoStr,token);
        } else {
            if (StringUtils.isNotBlank(loginKey)) {
                String userDtoStr = redisTemplate.opsForValue().get(loginKey);
                setUserArg(args, argFlag, empDTO, userDtoStr,token);
            }
        }
        return pj.proceed(args);
    }

    private void setUserArg(Object[] args, int argIndex, EmpDTO user, String userDtoStr,String token) {
        if (user instanceof StageEmpDTO) {
            user = JSONObject.parseObject(userDtoStr, StageEmpDTO.class);
        } else {
            user = JSONObject.parseObject(userDtoStr, AppletEmpDTO.class);
        }
        user.setToken(token);
        args[argIndex] = user;
    }

}
